#include<pthread.h>
#include<stdio.h>

int buffer1[4],buffer2[4];
pthread_mutex_t mutex1,mutex2;
int buffer1_in=0,buffer1_out=0,buffer2_in=0,buffer2_out=0;
pthread_cond_t wait_buffer1_empty,wait_buffer1_full,wait_buffer2_empty,wait_buffer2_full;

int buffer_is_empty(int x)
{
    if(x==1)
        return buffer1_in == buffer1_out;
    else
        return buffer2_in == buffer2_out;
}

int buffer_is_full(int x)
{
    if(x==1)
        return (buffer1_in+1)%4 == buffer1_out;
    else
        return (buffer2_in+1)%4 == buffer2_out;
}

void put_item(int item,int x)
{
    if(x==1)
    {
        buffer1[buffer1_in]=item;
        buffer1_in=(buffer1_in+1)%4;
    }
    else
    {
        buffer2[buffer2_in]=item;
        buffer2_in=(buffer2_in+1)%4;
    }
}

int get_item(int x)
{
    int item;
    if(x==1)
    {
        item=buffer1[buffer1_out];
        buffer1_out=(buffer1_out+1)%4;
    }
    else
    {
        item=buffer2[buffer2_out];
        buffer2_out=(buffer2_out+1)%4;
    }
    return item;
}

void *producer(void *arg)
{
    int item;
    for(int i=0;i<8;i++)
    {
        pthread_mutex_lock(&mutex1);
        while(buffer_is_full(1))
            pthread_cond_wait(&wait_buffer1_empty,&mutex1);
        item='a' + i;
        put_item(item,1);
        pthread_cond_signal(&wait_buffer1_full);
        pthread_mutex_unlock(&mutex1);
    }
}

void *consumer(void *arg)
{
    int item;
    for(int i=0;i<8;i++)
    {
        pthread_mutex_lock(&mutex2);
        while(buffer_is_empty(2))
        {
            pthread_cond_wait(&wait_buffer2_full,&mutex2);
        }
        item=get_item(2);
        printf("%c\n",item);
        pthread_cond_signal(&wait_buffer2_empty);
        pthread_mutex_unlock(&mutex2);
    }
}

void *counter(void *arg)
{
    int item;
    for(int i=0;i<8;i++)
    {
        pthread_mutex_lock(&mutex1);
        while(buffer_is_empty(1))
            pthread_cond_wait(&wait_buffer1_full,&mutex1);
        item=get_item(1);
        pthread_cond_signal(&wait_buffer1_empty);
        pthread_mutex_unlock(&mutex1);

        pthread_mutex_lock(&mutex2);
        while(buffer_is_full(2))
            pthread_cond_wait(&wait_buffer2_empty,&mutex2);
        item-=32;
        put_item(item,2);
        pthread_cond_signal(&wait_buffer2_full);
        pthread_mutex_unlock(&mutex2);
    }
}

int main()
{
    pthread_t producer_tid,consumer_tid,counter_tid;
    pthread_mutex_init(&mutex1,NULL);
    pthread_mutex_init(&mutex2,NULL);
    pthread_cond_init(&wait_buffer1_empty,NULL);
    pthread_cond_init(&wait_buffer1_full,NULL);
    pthread_cond_init(&wait_buffer2_empty,NULL);
    pthread_cond_init(&wait_buffer2_full,NULL);
    pthread_create(&producer_tid,NULL,producer,NULL);
    pthread_create(&counter_tid,NULL,counter,NULL);
    pthread_create(&consumer_tid,NULL,consumer,NULL);
    pthread_join(producer_tid,NULL);
    pthread_join(counter_tid,NULL);
    pthread_join(consumer_tid,NULL);
    return 0;
}
